import ConfigParser
import os
from .. import External

def readNCBIDatabase(db):
	""" Read a given database formatted in blastdb format,
	using external resources (fastacmd). Returns the database
	as a raw fasta output
	"""
	command = External.get("fastacmd", "path")
	options = ' -D 1 -d ' + db
	spool = ''
	thisDir = os.getcwd()

	if '/' not in db:
		# if no directory is given, assume that is the
		# one specified in external.ini
		os.chdir(External.get("blastdb", "path"))

	p = os.popen(command + options, 'r')
	while 1:
		l = p.readline()
		if not l:
			break
		spool += l
	p.close()
	os.chdir(thisDir)
	return spool

def dumpNCBIAccessions(db):
	""" Read a given database formatted in blastdb format,
	using external resources (fastacmd). Returns protein accession
	list
	"""

	command = External.get("fastacmd", "path")
	options = ' -D 3 -d ' + db
	acclist = []
	thisDir = os.getcwd()

	if '/' not in db:
		# if no directory is given, assume that is the
		# one specified in external.ini
		os.chdir(External.get("blastdb", "path"))

	p = os.popen(command + options, 'r')
	while 1:
		l = p.readline()
		if not l:
			break
		acclist.append(l.strip())
	p.close()
	os.chdir(thisDir)
	return acclist

def readEntryFromNCBI(db, accession):
	""" Get a single protein entry from a blastdb database
	and give it back as a tuple
	
	entry = (accession, description, sequence)
	"""
	entry = ()
	sequence = ''
	command = External.get("fastacmd", "path")
	options = ' -d ' + db + ' -s ' + accession
	thisDir = os.getcwd()

	if '/' not in db:
		# if no directory is given, assume that is the
		# one specified in external.ini
		os.chdir(External.get("blastdb", "path"))

	p = os.popen(command + ' ' + options, 'r')
	while 1:
		l = p.readline()
		if not l:
			break
		if l[0] == '>':
			# this is the definition line
			# split to get the accession (should be the same 
			# that the one provided) and strip definition line as description
			entry += (l.split('|')[1].split(' ')[0], l[1:].strip())
		else:
			# add sequence all uppercase and without newline chars
			sequence += l.upper().strip()
	p.close()
	# add the sequence to the parsed entry and return it
	entry += (sequence,)
	os.chdir(thisDir)
	return entry
	
def writeNCBI(fastaFile, dbname = '', title = ''):
	""" This function uses external resource "formatdb"
	to convert a fasta file into a blastdb database
	and returns the database name
	"""
	command = External.get("formatdb", "path")
	
	# change directory to database directory
	thisDir = os.getcwd()
	
	if '/' not in fastaFile:
	
		# if no directory is given, assume that is the
		# one specified in external.ini
		os.chdir(External.get("blastdb", "path"))
	#set the name, that is fastaFile without any .fa or .fasta extension
	if not dbname:
		p = fastaFile.find('.fa')
		if p != -1:
			dbname = fastaFile[:p]
		else:
			dbname = fastaFile
	
	# remove directories from dbname
	dbname = dbname[1 + dbname.rfind('/'):]
	
	# prepare an array for formatdb command
	realcmd = [command, 
	'-i', fastaFile, 
	'-n', dbname, 
	'-o', 'T', 
	'-p', 'T',
	'-t', title]
	
	# execute formatdb
	exit = os.spawnv(os.P_WAIT, realcmd[0], realcmd)
	
	# go back to original directory
	os.chdir(thisDir)
	
	# return the database name, for new queries
	if exit == 0:
		return dbname
	else:
		return False
		
def writeFasta(entryList, fastaFile):
	""" accepts a sequence entry as a tuple
	
	entry = (accession, description, sequence)
	
	and writes it into a fasta file.
	"""
	linewrap = 80
	thisDir = os.getcwd()

	if '/' not in fastaFile:
		# if no directory is given, assume that is the
		# one specified in external.ini
		os.chdir(External.get("blastdb", "path"))
	
	fh = open(fastaFile, 'w')
	
	for entryTuple in entryList:
		fh.write('>' + entryTuple[1] + '\n')
		for i in range(len(entryTuple[2]) / linewrap):
			fh.write(entryTuple[2][i * linewrap:i * linewrap + linewrap] + '\n')
		r = len(entryTuple[2]) % linewrap
		fh.write(entryTuple[2][-r:] + '\n')
	
	fh.close()
	os.chdir(thisDir)


def appendToFasta(entryTuple, fastaFile, mode=1):
	""" accepts a sequence entry as a tuple
	
	entry = (accession, description, sequence)
	
	and writes it into a fasta file.
	Mode 1 means that each entry is appended to an existing file
	Mode 0 overwrites any single entry...
	"""

	modes = ['w', 'a']
	linewrap = 80
	thisDir = os.getcwd()

	if '/' not in fastaFile:
		# if no directory is given, assume that is the
		# one specified in external.ini
		os.chdir(External.get("blastdb", "path"))
	
	if mode == 2:
		unlink(fastaFile)
		mode = 1

	fh = open(fastaFile, modes[mode])
	fh.write('>' + entryTuple[1] + '\n')
	for i in range(len(entryTuple[2]) / linewrap):
		fh.write(entryTuple[2][i * linewrap:i * linewrap + linewrap] + '\n')
	r = len(entryTuple[2]) % linewrap
	fh.write(entryTuple[2][-r:] + '\n')
	fh.close()
	os.chdir(thisDir)
	
